/**
 * 函数currying
 * [https://juejin.cn/post/6844903885488783374]
 *  */
//#region 
function sum(...args1) {
    let sum = args1.reduce((total, curr) => total + (Number(curr) || 0), 0);

    function calcTotal(...args2) {
        sum += args2.reduce((total, curr) => total + (Number(curr) || 0), 0);
        return calcTotal;
    }
    calcTotal.toString = function () {
        return sum;
    };
    return calcTotal;
}
// console.log(sum(1)(2, 3)(4, 5, 6)(7, 8, 9));
//#endregion

// TODO apply, call ,binb 实现

//#region 
Function.prototype.myApply = function (that, arr) {
    that = that || window;
    that._tempFn = this;
    if (!arr) {
        that._tempFn();
        delete that._tempFn;
    } else {
        if (!Array.isArray(arr)) {
            throw new Error("argArray mus be array");
        } else {
            that._tempFn(...arr);
            delete that._tempFn;
        }
    }
};
Function.prototype.myCall = function (that, ...args) {
    that = that || window;
    that._tempFn = this;
    if (!args.length) {
        that._tempFn();
        delete that._tempFn;
    } else {
        that._tempFn(args);
        delete that._tempFn;
    }
};
const name = "WINDOW";

function f2(...args) {
    console.log(this.name, ...args);
}
var obj = {
    name: "Yusup",
};
// f2.myApply(null, [1, 2, 3]);
// f2.myApply(obj, [4, 5, 6]);

// f2.myCall(null, 1, 2, 3);
// f2.myCall(obj, 4, 5, 6);
Function.prototype.myBind = function (that, ...args) {
    that = that || window;
    that._tempFn = this;
    let temp = () => {
        this.apply(that, args);
    };
    return temp;
};
// let f3 = f2.myBind(obj, 1, 2, 3);
// f3();

// const foo = new Foo(); // ReferenceError: Foo is not defined
// console.log(Foo);
// class Foo {
//     constructor() {
//         this.foo = 42;
//     }
// }
//#endregion

//TODO 第 11 题：（携程）算法手写题
//#region 
/* ! function() {
    let arr = [
        [1, 2, 2],
        [3, 4, 5, 5],
        [6, 7, 8, 9, [11, 12, [12, 13, [14]]]], 10
    ];

    function flatArr(arr, temp = []) {
        for (let i = 0; i < arr.length; i++) {
            if (Array.isArray(arr[i])) {
                flatArr(arr[i], temp)
            } else {
                temp.push(arr[i])
            }
        }
        return temp
    }
    console.log(flatArr(arr));

    function flatten(arr) {
        return arr.reduce((result, item) => {
            return result.concat(Array.isArray(item) ? flatten(item) : item);
        }, []);
    }
    console.log(flatten(arr));
}() */
//#endregion

//TODO  第 14 题：如何实现一个 new
//#region 
/* ! function() {
    function _new(fn, ...args) {
        let obj = Object.create(fn.prototype);
        let ret = fn.apply(obj, args);
        return ret instanceof Object ? ret : obj;
    }

    function Animal(name) {
        this.name = name;
    };
    Animal.prototype.sayName = function() {
        console.log(this.name);
    }
    let cat = _new(Animal, 'Yusup');
    console.log(cat.sayName());
}() */
//#endregion

// TODO 为什么通常在发送数据埋点请求的时候使用的是 1x1 像素的透明 gif 图片？
//#region 
/*
作用：工作中，用于前端监控，比如曝光等等，谷歌和百度的都是用的1x1 像素的透明 gif 图片；
why ?
没有跨域问题，一般这种上报数据，代码要写通用的；（排除ajax）
不会阻塞页面加载，影响用户的体验，只要new Image对象就好了；（排除JS / CSS文件资源方式上报）
在所有图片中，体积最小；（比较PNG / JPG）
能够完成整个 HTTP 请求+响应（尽管不需要响应内容）
触发 GET 请求之后不需要获取和处理数据、服务器也不需要发送数据
跨域友好
执行过程无阻塞
相比 XMLHttpRequest 对象发送 GET 请求，性能上更好
GIF的最低合法体积最小（最小的BMP文件需要74个字节，PNG需要67个字节，而合法的GIF，只需要43个字节）
*/
//#endregion

// TODO （百度）实现 (5).add(3).minus(2) 功能。
//#region 
/* ! function() {
    Number.prototype.add = function(num) {
        return this + num
    };
    Number.prototype.minus = function(num) {
        return this - num
    };
    console.log((5).add(8).minus(2));
}() */
//#endregion

// TODO 第 55 题：某公司 1 到 12 月份的销售额存在一个对象里面
//#region 
/**
 * {如下：{1:222, 2:123, 5:888}，请把数据处理为如下结构：[222, 123, null, null, 888, null, null, null, null, null, null, null]。}
 *  */
/* ! function() {
    //* 方法一
    let obj = { 1: 222, 2: 123, 5: 888 };
    let temp = [];

    for (i = 1; i <= 12; i++) {
        if (obj[i]) {
            temp.push(obj[i])
        } else {
            temp.push(null)
        }
    }
    console.log(temp);
    //* 方法二
    obj.length = 12;
    temp = Array.from(obj, (v, k) => v ? v : null);
    console.log(temp);
}() */
//#endregion

// TODO 第 56 题：要求设计 LazyMan 类，实现以下功能。
//#region 
/*
LazyMan('Tony');
// Hi I am Tony

LazyMan('Tony').sleep(10).eat('lunch');
// Hi I am Tony
// 等待了10秒...
// I am eating lunch

LazyMan('Tony').eat('lunch').sleep(10).eat('dinner');
// Hi I am Tony
// I am eating lunch
// 等待了10秒...
// I am eating diner

LazyMan('Tony').eat('lunch').eat('dinner').sleepFirst(5).sleep(10).eat('junk food');
// Hi I am Tony
// 等待了5秒...
// I am eating lunch
// I am eating dinner
// 等待了10秒...
// I am eating junk food
*/

! function () {
    /* function LazyMan(name) {
        this.name = name;
        this.time = 0;
        this.sleepFirstTime = 0;
        if (!(this instanceof LazyMan)) {
            return new LazyMan(name)
        }
        console.log(`Hi I am ${name}`);
        this.sleep = function(time) {
            this.time = time * 1000;
            setTimeout(() => {
                console.log(`等待了${time}秒...`);
            }, time * 1000);
            return this;
        };
        this.eat = function(something) {
            setTimeout(() => {
                console.log(`I am eating ${something}`);
                this.time = 0;
            }, this.time);
            return this;
        }
        this.sleepFirst = function(time) {
            this.sleepFirstTime = time * 1000
            if (this.time) {
                this.time += time * 1000
            }
            setTimeout(() => {
                console.log(`等待了${time}秒...`);
            }, time * 1000);
        }
    }; */
    // LazyMan('Tony').sleep(3).eat('lunch').eat('dinner').sleepFirst(5);

}()
//#endregion

// TODO nodejs 的 eventEmitter 的实现

// TODO requestAnimationFrame和requestdlecallback，除了这两个API的使用，还具体问了准确的执行时机

// TODO rem布局原理和使用，原理大家都知道，根据的是根元素的font-size属性。还需要清楚具体使用rem布局的时候，如何去设置根元素的font-size大小，才能让页面在不同屏幕大小看以来一致。

// TODO 手写instanceof
//#region 
/* !(() => {
    function instace_of(instance, constructorFn) {
        console.log(typeof instance);
        const baseType = ['string', 'number', 'boolean', 'undefined', 'symbol'];
        if (baseType.includes(typeof instance)) return false
        let proto = constructorFn.prototype;
        console.dir(instance);
        instance = instance.__proto__;
        console.log();
        while (true) {
            console.log(instance);
            if (instance == null) return false
            if (instance === proto) return true;
            instance = instance.__proto__
        }
    }
    console.log((instace_of(1, Number)))
 
 
    function Animal(name) {
        this.name = name
    }
    let instance1 = new Animal('cat')
    console.log(instace_of(instance1, Animal));
})() */
//#endregion

// TODO 防抖 - 节流

!(() => {
    console.log(11);
    //* 节流  在持续触发事件的过程中，函数会立即执行，并且每 1s 执行一次。
    function throttle(fn, time) {
        let lastTime = 0;
        return function (...args) {
            let now = Date.now();
            if (now - lastTime >= time) {
                fn.apply(this, args)
                lastTime = Date.now()
            }
        }
    }

    //! 防抖 持续触发事件时，debounce 会合并事件且不会去触发事件，当一定时间内没有触发再这个事件时，才真正去触发事件。 
    function debounce(fn, time) {
        let timeout;
        return function (...args) {
            if (timeout) clearTimeout(timeout);
            timeout = setTimeout(() => {
                fn.apply(this, args)
            }, time);
        }
    }
    function fn(target, event) {
        console.log(this, target, event);
    }
    // document.onmousemove = debounce(fn, 1000)

    document.querySelector('button').onclick = debounce(fn, 500)
})()